package com.czy.workflow.core.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.czy.workflow.core.model.*;
import com.czy.workflow.core.service.FlowService;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * Created by admin on 2019/8/31.
 */


@Service("jsonFlowService")
public class JsonFlowService implements FlowService {

    Logger logger = Logger.getLogger(JsonFlowService.class.getName());

    private Map<String, FlowMain> flowMains = new HashMap<>();
    private Map<String, List> currentNodes = new ConcurrentHashMap<>();

    public JsonFlowService() {
        try {
            loadFromJsonFile("classpath:json/F1.json");
            loadFromJsonFile("classpath:json/F2.json");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void loadFromJsonFile(String path) throws Exception{
        File file = ResourceUtils.getFile(path);
        if(FileUtil.exist(file)){
            JSONObject json = JSONUtil.readJSONObject(file, Charset.forName("utf-8"));
            FlowMain flowMain = JSONUtil.toBean(json, FlowMain.class);
            //解决node对象json化为空的问题
            flowMain.setNodes(new ArrayList<>());
            JSONArray array = json.getJSONArray("nodes");
            for(int i=0; i<array.size(); i++){
                JSONObject obj = array.getJSONObject(i);
                FlowNode node = new FlowNode();
                node.setId(obj.getStr("id"));
                node.setFlowId(flowMain.getId());
                node.setCode(obj.getStr("code"));
                node.setOperationType(OperationType.newInstance(obj.getStr("operationType")));
                flowMain.getNodes().add(node);
            }

            for(FlowBranch branch : flowMain.getBranches()){
                branch.setFlowId(flowMain.getId());
            }

            flowMains.put(flowMain.getId(), flowMain);

            logger.info("load json file : " + path);
        }
    }

    @Override
    public boolean saveFlowMain(FlowMain flowMain) {
        return false;
    }

    @Override
    public FlowMain getFlowMainById(String flowId) {
        return flowMains.get(flowId);
    }

    @Override
    public FlowNode getFlowNodeById(String flowId, String nodeId) {
        FlowMain flowMain = getFlowMainById(flowId);
        for(FlowNode node : flowMain.getNodes()){
            if(nodeId.equals(node.getId())){
                return node;
            }
        }
        return null;
    }

    @Override
    public List<FlowNode> getNextNodes(String flowId, String nodeId) {
        List<FlowNode> nextNodes = new ArrayList<>();
        FlowMain flowMain = getFlowMainById(flowId);
        for(FlowBranch flowBranch : flowMain.getBranches()){
            if(nodeId.equals(flowBranch.getSourceNodeId())){
                nextNodes.add(getFlowNodeById(flowId, flowBranch.getTargetNodeId()));
            }
        }
        return nextNodes;
    }

    @Override
    public List<FlowBranch> getNodeBranches(String flowId, String nodeId) {
        FlowMain flowMain = getFlowMainById(flowId);
        List<FlowBranch> nodeBranches = flowMain.getBranches().stream().filter((FlowBranch tmp)->nodeId.equals(tmp.getSourceNodeId())).collect(Collectors.toList());
        return nodeBranches;
    }

    @Override
    public List<FlowNode> getStartNodes(String flowId) {
        FlowMain flowMain = getFlowMainById(flowId);
        List<FlowNode> startNodes = flowMain.getNodes().stream().filter((FlowNode tmp)->OperationType.START==tmp.getOperationType()).collect(Collectors.toList());
        return startNodes;
    }

    @Override
    public boolean refreshCurrentNodes(String docId, String currentNodeId, List<FlowNode> nodes) {
        //只能用于单线程
        currentNodes.put(docId, nodes);
        return true;
    }

    @Override
    public boolean clearCurrentNodes(String docId) {
        currentNodes.remove(docId);
        return true;
    }

    @Override
    public boolean existCurrentNode(String docId, String currentNodeId) {
        return true;
    }

    @Override
    public List<FlowNode> getCurrentNodes(String docId) {
        return currentNodes.get(docId);
    }

    @Override
    public FlowOrgElement getCurrentUser() {
        return null;
    }

    @Override
    public boolean saveFlowLog(TaskInfo taskInfo, boolean result) {
        return false;
    }

    @Override
    public TaskInfo getTaskInfoByDocId(String docId, String nodeId) {

        List<FlowNode> currentNodes = this.getCurrentNodes(docId);
        currentNodes = currentNodes.stream().filter((FlowNode tmp)->tmp.getId().equals(nodeId)).collect(Collectors.toList());
        if(currentNodes.size() <= 0){
            return null;
        }

        FlowNode currentNode = currentNodes.get(0);
        FlowMain flowMain = this.getFlowMainById(currentNode.getFlowId());

        TaskInfo taskInfo = new TaskInfo();
        taskInfo.setNode(currentNode);
        taskInfo.setFlowId(flowMain.getId());
        taskInfo.setFlowCode(flowMain.getCode());
        taskInfo.setDocId(docId);

        return taskInfo;
    }

    @Override
    public boolean validateNodeAuthority(TaskInfo taskInfo) {
        return true;
    }
}
